/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package kpsmart.gui;

import java.awt.event.*;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.xml.bind.JAXBException;
import kpsmart.model.business.Business;
import kpsmart.model.business.KeyBusinessFigures;
import kpsmart.model.events.Event;
import kpsmart.model.events.Events;
import kpsmart.model.routes.ChainedRoute;
import kpsmart.model.routes.RouteTuple;
import kpsmart.model.routes.Routes;

/**
 * Controller class. Deals with the interaction between model and view.
 * Implements all necessary listeners for view and dialogs.
 *
 * @author Oliver Behncke
 * @author John Quinlivan
 */
public class Controller {
    // The path of the database. Will be removed after the server starts working

    private static final String LOGFILEPATH = "data/database.xml";
    // View is final
    private final View view;
    // Model is final as well
    private final Model model;

    /**
     * Private controller will be called by main method.
     */
    private Controller() {

        // this listener listens to any changes in the model.
        ChangeListener cl = new ChangeListener() {

            @Override
            public void change() {
                try {
                    reload();
                    setKBFRegular();
                    updateEventList();
                } catch (JAXBException ex) {
                    Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };
        model = new Model(LOGFILEPATH, cl);
        view = new View();
        try {
            updateEventList();
        } catch (JAXBException ex) {
            dbErrorGeneral(view);
            view.dispose();
        }

        view.addListenerToReconnect(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                model.reconnect();
            }

        });
        // add listener to the list of events in the manager view
        view.addListenerToEventList(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {
                try {
                    Event event = model.getEvent(view.getSelectedIndexEventList());
                    if (event != null) {
                        view.setDetailText(event.toStringDetail());
                        KeyBusinessFigures kbf = Business.keyBusinessFigures(model.getEvents(), event);
                        view.setManagerMail(kbf.getTotalNumberOfMailItems());
                        view.setManagerExpenditure(kbf.getExpenditure());
                        view.setManagerRevenue(kbf.getRevenue());
                        view.setManagerEvents(kbf.getTotalNumberOfEvents());
                        view.setManagerWeight(kbf.getTotalWeightOfMailItems());
                        view.setManagerVolume(kbf.getTotalVolumeOfMailItems());
                        Object[] columnNames1 = {"From", "To", "Priority", "Average delivery time", "Mail Items", "Total weight", "Total volume"};
                        view.setManagerDetailsTable(mapToTableData(kbf.getAverageDeliveryTimes(), kbf.getMailPerRoute(), kbf.getWeightPerRoute(), kbf.getVolumePerRoute()), columnNames1);
                        Object[] columnNames2 = {"From", "To", "Priority", "Average loss"};
                        view.setManagerCriticalRoutesTable(mapToTableData(kbf.getCriticalRoutes()), columnNames2);
                    }
                } catch (JAXBException ex) {
                    Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        // add listener to the cost update button
        view.addListenerToCostUpdate(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                final CostForm form = new CostForm();
                form.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                form.setTypes(Routes.getRouteTypes());
                form.setDays(Routes.getDays());

                form.addWindowListener(new WindowAdapter() {

                    @Override
                    public void windowClosing(WindowEvent e) {
                        view.setEnabled(true);
                        form.dispose();
                    }
                });

                form.addListenerToCancel(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        view.setEnabled(true);
                        form.dispose();
                    }
                });

                // add listener to submit button
                form.addListenerToSubmit(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        String company = form.getCompany();
                        String from = form.getFrom();
                        String to = form.getTo();
                        String type = form.getRoutetype();

                        String day = form.getDay();
                        if (!form.properDuration()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for duration", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properFrequency()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for frequency", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properMaxWeight()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for max. weight", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properMaxVolume()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for max. volume", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properWeightcost()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for weight cost", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properVolumecost()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for volume cost", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else {
                            int duration = form.getDuration();
                            int frequency = form.getFrequency();
                            int maxWeight = form.getMaxWeight();
                            int maxVolume = form.getMaxVolume();
                            int volumecost = form.getVolumecost();
                            int weightcost = form.getWeightcost();
                            if (company.trim().equals("")) {
                                JOptionPane.showMessageDialog(form, "Company cannot be empty", "No company", JOptionPane.ERROR_MESSAGE);
                            } else if (from.trim().equals("")) {
                                JOptionPane.showMessageDialog(form, "Field \"From\" cannot be empty", "No \"From\"", JOptionPane.ERROR_MESSAGE);
                            } else if (to.trim().equals("")) {
                                JOptionPane.showMessageDialog(form, "Field \"To\" cannot be empty", "No \"To\"", JOptionPane.ERROR_MESSAGE);
                            } else if (duration <= 0) {
                                JOptionPane.showMessageDialog(form, "Duration cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (frequency <= 0) {
                                JOptionPane.showMessageDialog(form, "Frequency cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (maxWeight <= 0) {
                                JOptionPane.showMessageDialog(form, "Max. weight cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (maxVolume <= 0) {
                                JOptionPane.showMessageDialog(form, "Max. volume cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (weightcost < 0) {
                                JOptionPane.showMessageDialog(form, "Weightcost cannot be less than zero", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (volumecost < 0) {
                                JOptionPane.showMessageDialog(form, "Volumecost cannot be less than zero", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else {
                                try {
                                    model.saveEvent(Events.createCostType(company, to, from, type, weightcost, volumecost, maxWeight, maxVolume, duration, frequency, day, new java.util.Date().getTime()));
                                    view.setEnabled(true);
                                    form.dispose();
                                } catch (JAXBException ex) {
                                    dbErrorItem(form);
                                } catch (FileNotFoundException ex) {
                                    dbErrorItem(form);
                                }
                            }


                        }
                    }
                });
                form.setVisible(
                        true);
                view.setEnabled(
                        false);
            }
        });

        // add listener to the edit button
        view.addListenerToEdit(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    final EditForm form = new EditForm(model.getActiveCostTypes());
                    form.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    form.setTypes(Routes.getRouteTypes());
                    form.setDays(Routes.getDays());

                    form.addWindowListener(new WindowAdapter() {

                        @Override
                        public void windowClosing(WindowEvent e) {
                            view.setEnabled(true);
                            form.dispose();
                        }
                    });

                    form.addListenerToCancel(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent ae) {
                            view.setEnabled(true);
                            form.dispose();
                        }
                    });

                    // add listener to submit button
                    form.addListenerToSubmit(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent ae) {
                            String company = form.getCompany();
                            String from = form.getFrom();
                            String to = form.getTo();
                            String type = form.getRoutetype();

                            String day = form.getDay();
                            if (!form.properDuration()) {
                                JOptionPane.showMessageDialog(form, "Illegal value for duration", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (!form.properFrequency()) {
                                JOptionPane.showMessageDialog(form, "Illegal value for frequency", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (!form.properMaxWeight()) {
                                JOptionPane.showMessageDialog(form, "Illegal value for max. weight", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (!form.properMaxVolume()) {
                                JOptionPane.showMessageDialog(form, "Illegal value for max. volume", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (!form.properWeightcost()) {
                                JOptionPane.showMessageDialog(form, "Illegal value for weight cost", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else if (!form.properVolumecost()) {
                                JOptionPane.showMessageDialog(form, "Illegal value for volume cost", "Illegal value", JOptionPane.ERROR_MESSAGE);
                            } else {
                                int duration = form.getDuration();
                                int frequency = form.getFrequency();
                                int maxWeight = form.getMaxWeight();
                                int maxVolume = form.getMaxVolume();
                                int volumecost = form.getVolumecost();
                                int weightcost = form.getWeightcost();
                                if (company.trim().equals("")) {
                                    JOptionPane.showMessageDialog(form, "Company cannot be empty", "No company", JOptionPane.ERROR_MESSAGE);
                                } else if (from.trim().equals("")) {
                                    JOptionPane.showMessageDialog(form, "Field \"From\" cannot be empty", "No \"From\"", JOptionPane.ERROR_MESSAGE);
                                } else if (to.trim().equals("")) {
                                    JOptionPane.showMessageDialog(form, "Field \"To\" cannot be empty", "No \"To\"", JOptionPane.ERROR_MESSAGE);
                                } else if (duration <= 0) {
                                    JOptionPane.showMessageDialog(form, "Duration cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                } else if (frequency <= 0) {
                                    JOptionPane.showMessageDialog(form, "Frequency cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                } else if (maxWeight <= 0) {
                                    JOptionPane.showMessageDialog(form, "Max. weight cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                } else if (maxVolume <= 0) {
                                    JOptionPane.showMessageDialog(form, "Max. volume cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                } else if (weightcost < 0) {
                                    JOptionPane.showMessageDialog(form, "Weightcost cannot be less than zero", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                } else if (volumecost < 0) {
                                    JOptionPane.showMessageDialog(form, "Volumecost cannot be less than zero", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                } else {
                                    try {
                                        model.saveEvent(Events.createDiscontinueType(form.getOldTo(), form.getOldFrom(), form.getOldCompany(), form.getOldType(), form.getOldDate(), new java.util.Date().getTime()));
                                        model.saveEvent(Events.createCostType(company, to, from, type, weightcost, volumecost, maxWeight, maxVolume, duration, frequency, day, new java.util.Date().getTime()));
                                        view.setEnabled(true);
                                        form.dispose();
                                    } catch (JAXBException ex) {
                                        dbErrorItem(form);
                                    } catch (FileNotFoundException ex) {
                                        dbErrorItem(form);
                                    }
                                }


                            }
                        }
                    });
                    form.setVisible(
                            true);
                    view.setEnabled(
                            false);
                } catch (JAXBException ex) {
                    Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });

        // add listener to new mail button
        view.addListenerToNewMail(
                new ActionListener() {

                    private void updateTo(NewMailForm form) throws JAXBException {
                        form.setTo(Routes.getDestinationsForRoutes(model.getRoutes(form.getFrom())));
                        updatePriorities(form);
                    }

                    private void updatePriorities(NewMailForm form) throws JAXBException {
                        form.setPriorities(Routes.getPrioritiesForRoutes(model.getRoutes(form.getFrom(), form.getTo())));
                    }

                    void updatePriceAndDuration(NewMailForm form) {
                        if (!form.properWeight()) {
                            form.setPriceInfo("Illegal value for weight");
                            form.setDuration("");
                        }
                        else if (!form.properVolume()) {
                            form.setPriceInfo("Illegal value for volume");
                            form.setDuration("");
                        } else {
                            try {
                                ChainedRoute route = getRoute(form);

                                if (route == null) {
                                    form.setPriceInfo("<HTML><p>No route for given weight and volume</p><HTML>");
                                    form.setDuration("");
                                } else if (form.getWeight() <= 0) {
                                    form.setPriceInfo("<HTML><p>No price for negative or zero weight values</p><HTML>");
                                    form.setDuration("");
                                } else if (form.getVolume() <= 0) {
                                    form.setPriceInfo("<HTML><p>No price for negative or zero volume values</p><HTML>");
                                    form.setDuration("");
                                } else {
                                    int price = getPrice(form, route);
                                    if (price == -1) {
                                        form.setPriceInfo("<HTML><p>No price for given route, priority, weight and volume</p><HTML>");
                                        form.setDuration("");
                                    } else {
                                        form.setPriceInfo(Integer.valueOf(price).toString());
                                        form.setDuration(route.duration(new java.util.Date().getTime()) + " h");
                                    }
                                }
                            } catch (JAXBException ex) {
                                Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }

                    }

                    ChainedRoute getRoute(NewMailForm form) throws JAXBException {
                        return model.getRoute(form.getFrom(), form.getTo(), form.getPriority(), form.getWeight(), form.getVolume());
                    }

                    int getPrice(NewMailForm form, ChainedRoute route) throws JAXBException {
                        return model.getPriceForRoute(route, form.getPriority(), form.getWeight(), form.getVolume());
                    }

                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        final NewMailForm form = new NewMailForm();
                        try {

                            form.addWindowListener(new WindowAdapter() {

                                @Override
                                public void windowClosing(WindowEvent e) {
                                    view.setEnabled(true);
                                    form.dispose();
                                }
                            });

                            form.addListenerToCancel(new ActionListener() {

                                @Override
                                public void actionPerformed(ActionEvent ae) {
                                    view.setEnabled(true);
                                    form.dispose();
                                }
                            });
                            form.setFrom(model.getNZOrigins());
                            updateTo(form);
                            form.addListenerToFrom(new ActionListener() {

                                @Override
                                public void actionPerformed(ActionEvent ae) {
                                    try {
                                        updateTo(form);
                                        updatePriorities(form);
                                        updatePriceAndDuration(form);
                                    } catch (JAXBException ex) {
                                        Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                                }
                            });
                            form.addListenerToPriorities(new ActionListener() {

                                @Override
                                public void actionPerformed(ActionEvent ae) {
                                    updatePriceAndDuration(form);
                                }
                            });
                            form.addListenerToTo(new ActionListener() {

                                @Override
                                public void actionPerformed(ActionEvent ae) {
                                    try {
                                        updatePriorities(form);
                                        updatePriceAndDuration(form);
                                    } catch (JAXBException ex) {
                                        Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                                }
                            });
                            form.addFocusListenerToWandV(new FocusListener() {

                                @Override
                                public void focusGained(FocusEvent fe) {
                                    // Do nothing
                                }

                                @Override
                                public void focusLost(FocusEvent fe) {
                                    updatePriceAndDuration(form);
                                }
                            });
                            // add listener to submit button
                            form.addListenerToSubmit(new ActionListener() {

                                @Override
                                public void actionPerformed(ActionEvent ae) {
                                    if (!form.properWeight()) {
                                        JOptionPane.showMessageDialog(form, "Illegal value for weight", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                    }
                                    if (!form.properVolume()) {
                                        JOptionPane.showMessageDialog(form, "Illegal value for volume", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                    } else {
                                        try {

                                            ChainedRoute route = getRoute(form);
                                            if (route == null) {
                                                JOptionPane.showMessageDialog(form, "No route for given weight and volume", "No route", JOptionPane.ERROR_MESSAGE);
                                            } else {
                                                int price = getPrice(form, route);
                                                int weight = form.getWeight();
                                                int volume = form.getVolume();
                                                if (price == -1) {
                                                    JOptionPane.showMessageDialog(form, "No price for given route, priority, weight and volume", "No price", JOptionPane.ERROR_MESSAGE);
                                                } else if (weight <= 0) {
                                                    JOptionPane.showMessageDialog(form, "Weight cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                                } else if (volume <= 0) {
                                                    JOptionPane.showMessageDialog(form, "Volume cannot be zero or less", "Illegal value", JOptionPane.ERROR_MESSAGE);
                                                } else {
                                                    model.saveEvent(Events.createMailType(form.getDay(), form.getTo(), form.getFrom(), weight, volume, form.getPriority(), new java.util.Date().getTime()));
                                                    view.setEnabled(true);
                                                    form.dispose();
                                                }

                                            }
                                        } catch (FileNotFoundException ex) {
                                            dbErrorItem(form);
                                        } catch (JAXBException ex) {
                                            dbErrorItem(form);
                                        }
                                    }
                                }
                            });
                            view.setEnabled(false);
                            form.setVisible(true);

                        } catch (JAXBException ex) {
                            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                });
        // add listener to dicontinue button
        view.addListenerToDiscontinueUpdate(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    final DiscontinueForm form = new DiscontinueForm(model.getActiveCostTypes());
                    form.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

                    form.addWindowListener(new WindowAdapter() {

                        @Override
                        public void windowClosing(WindowEvent e) {
                            view.setEnabled(true);
                            form.dispose();
                        }
                    });

                    form.addListenerToCancel(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent ae) {
                            view.setEnabled(true);
                            form.dispose();
                        }
                    });

                    form.addListenerToSubmit(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent ae) {
                            try {
                                model.saveEvent(Events.createDiscontinueType(form.getTo(), form.getFrom(), form.getCompany(), form.getRoutetype(), form.getRoutedate(), new java.util.Date().getTime()));
                                view.setEnabled(true);
                                form.dispose();
                            } catch (JAXBException ex) {
                                Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                            } catch (FileNotFoundException ex) {
                                Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                            }

                        }
                    });
                    view.setEnabled(false);
                    form.setVisible(true);
                } catch (JAXBException ex) {
                    Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        // add listener to price button
        view.addListenerToPriceUpdate(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                final PriceForm form = new PriceForm();
                form.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                form.setPriorities(Routes.getPriorities());

                form.addWindowListener(new WindowAdapter() {

                    @Override
                    public void windowClosing(WindowEvent e) {
                        view.setEnabled(true);
                        form.dispose();
                    }
                });

                form.addListenerToCancel(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        view.setEnabled(true);
                        form.dispose();
                    }
                });

                // add listener to submit button
                form.addListenerToSubmit(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        if (form.getFrom().equals("")) {
                            JOptionPane.showMessageDialog(form, "From cannot be empty", "No origin", JOptionPane.ERROR_MESSAGE);
                        } else if (form.getTo().equals("")) {
                            JOptionPane.showMessageDialog(form, "From cannot be empty", "No origin", JOptionPane.ERROR_MESSAGE);
                        } else if (form.getFrom().equals("New Zealand") && form.getTo().equals("New Zealand") && form.getPriority().contains("International")) {
                            JOptionPane.showMessageDialog(form, "No international priority for domestic route allowed", "Wrong priority", JOptionPane.ERROR_MESSAGE);
                        } else if ((!form.getFrom().equals("New Zealand") || !form.getTo().equals("New Zealand")) && form.getPriority().contains("Domestic")) {
                            JOptionPane.showMessageDialog(form, "No domestic priority for international route allowed", "Wrong priority", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properWeightcost()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for weight", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (!form.properVolumecost()) {
                            JOptionPane.showMessageDialog(form, "Illegal value for volume", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (form.getWeightcost() < 0) {
                            JOptionPane.showMessageDialog(form, "Weightcost cannot be less than zero", "Illegal value", JOptionPane.ERROR_MESSAGE);
                        } else if (form.getVolumecost() < 0) {
                            JOptionPane.showMessageDialog(form, "Volumecost cannot be less than zero", "Illegal value", JOptionPane.ERROR_MESSAGE);

                        } else {
                            try {
                                model.saveEvent(Events.createPriceType(form.getTo(), form.getFrom(), form.getPriority(), form.getWeightcost(), form.getVolumecost(), new java.util.Date().getTime()));
                                view.setEnabled(true);
                                form.dispose();
                            } catch (JAXBException ex) {
                                dbErrorItem(form);
                            } catch (FileNotFoundException ex) {
                                dbErrorItem(form);
                            }
                        }
                    }
                });
                view.setEnabled(false);
                form.setVisible(true);
            }
        });
        view.setVisible(true);

    }

    /**
     * Main task is to create a new controller
     *
     * @param args
     * @throws JAXBException
     */
    public static void main(String[] args) throws JAXBException {
        Controller controller = new Controller();
    }

    /**
     * DB error message for item that couldn't be saved.
     *
     * @param form
     */
    private void dbErrorItem(JFrame form) {
        JOptionPane.showMessageDialog(form, "Item cannot be saved as a database error occured.", "Database error", JOptionPane.ERROR_MESSAGE);
    }

    /**
     * DB error for general database error - DB not loadable.
     *
     * @param form
     */
    private void dbErrorGeneral(JFrame form) {
        JOptionPane.showMessageDialog(form, "Database couldn't be loaded.", "Database error", JOptionPane.ERROR_MESSAGE);
    }

    /**
     * Reload the model and update the event list.
     *
     * @throws JAXBException
     */
    private void reload() throws JAXBException {
        model.reload();

        if (view != null) {
            view.setEventList(eventsToString(model.getEvents()));
        }
    }

    /**
     * Set the KBF information in the regular view
     *
     * @throws JAXBException
     */
    private void setKBFRegular() throws JAXBException {
        KeyBusinessFigures kbf = Business.keyBusinessFigures(model.getEvents());
        view.setRegularMail(kbf.getTotalNumberOfMailItems());
        view.setRegularExpenditure(kbf.getExpenditure());
        view.setRegularRevenue(kbf.getRevenue());
        view.setRegularEvents(kbf.getTotalNumberOfEvents());
        view.setRegularWeight(kbf.getTotalWeightOfMailItems());
        view.setRegularVolume(kbf.getTotalVolumeOfMailItems());
        Object[] columnNames1 = {"From", "To", "Priority", "Average delivery time", "Mail Items", "Total weight", "Total volume"};
        view.setRegularDetailsTable(mapToTableData(kbf.getAverageDeliveryTimes(), kbf.getMailPerRoute(), kbf.getWeightPerRoute(), kbf.getVolumePerRoute()), columnNames1);
        Object[] columnNames2 = {"From", "To", "Priority", "Average loss"};
        view.setRegularCriticalRoutesTable(mapToTableData(kbf.getCriticalRoutes()), columnNames2);
    }

    /**
     * Update the event list in the manager view
     *
     * @throws JAXBException
     */
    private void updateEventList() throws JAXBException {
        view.setEventList(eventsToString(model.getEvents()));
    }

    /**
     * Helper function to convert a List of Events to a List of String
     *
     * @param list
     * @return
     */
    private static List<String> eventsToString(List<Event> list) {
        List<String> result = new ArrayList<String>(list.size());
        for (Event e : list) {
            result.add(e.toString());
        }
        return result;
    }

    /**
     * Transform 4 maps into an 2D Object array to make it displayable in a
     * table
     *
     * @param map0
     * @param map1
     * @param map2
     * @param map3
     * @return 2D Object Array
     */
    private static Object[][] mapToTableData(Map<RouteTuple, Double> map0, Map<RouteTuple, Integer> map1, Map<RouteTuple, Integer> map2, Map<RouteTuple, Integer> map3) {
        List<Object[]> arrays = new LinkedList<Object[]>();
        for (Map.Entry<RouteTuple, Double> entry : map0.entrySet()) {
            Object[] array = {entry.getKey().getFrom(), entry.getKey().getTo(), entry.getKey().getPriority(), entry.getValue(), map1.get(entry.getKey()), map2.get(entry.getKey()), map3.get(entry.getKey())};
            arrays.add(array);
        }
        if (arrays.isEmpty()) {
            return null;
        } else {
            Object[][] result = new Object[arrays.size()][];
            for (int i = 0; i < arrays.size(); i++) {
                result[i] = arrays.get(i);
            }
            return result;
        }
    }

    /**
     * Transform a map into an 2D Object array to make it displayable in a table
     *
     * @param map
     * @return
     */
    private static Object[][] mapToTableData(Map<RouteTuple, Double> map) {
        List<Object[]> arrays = new LinkedList<Object[]>();
        for (Map.Entry<RouteTuple, Double> entry : map.entrySet()) {
            Object[] array = {entry.getKey().getFrom(), entry.getKey().getTo(), entry.getKey().getPriority(), entry.getValue()};
            arrays.add(array);
        }
        if (arrays.isEmpty()) {
            return null;
        } else {
            Object[][] result = new Object[arrays.size()][];
            for (int i = 0; i < arrays.size(); i++) {
                result[i] = arrays.get(i);
            }
            return result;
        }
    }
}
